﻿using Microsoft.AspNetCore.Mvc;
using MVCDemo.Models;
using MVCDemo.Models.Database;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace MVCDemo.Controllers
{
    //特性路由 仅在这个控制器生效 并且 会让常规路由失效
    [Route("[controller]/[action]")]
    [Route("api/[controller]/[action]")]
    public class TestController : Controller
    {
        //私有的 只读     数据库上下文类   对象
        private readonly Store_2022Context _db;
        //第二种方法 依赖注入
        /// <summary>
        /// TestController类的构造方法 类在实例化的时候 首先调用的方法
        /// 初始化操作 数据上下文 对象 数据操作（增删改查）
        /// </summary>
        public TestController(Store_2022Context db)
        {
            // 赋值
            _db = db;
        }

        /// <summary>
        /// 方法
        /// </summary>
        /// <returns></returns>
        //特性路由 仅在这方法生效 并且 会让控制器的路由失效
        public IActionResult Index()
        {
            //第一种 不建议使用
            using (var db = new Store_2022Context())
            {
                db.Categories.Add(new Category()
                {
                    CateName = "分类1"
                });
            }


            //帮我们去找页面（视图View）
            //默认规则 Views文件夹/Test（控制器的名字）文件夹/Index（方法的名字）.cshtml
            return View();
            //指定视图路径 home控制器
           // return View("/home/index.cshtml");
        }
        /// <summary>
        /// 第二个页面的方法
        /// </summary>
        /// <returns></returns>
        public IActionResult Two()
        {
            //职责 查询数据 

            //把数据返回到页面上 怎么返回数据？？数据传递
            return View();
        }

        public IActionResult ViewDataDemo()
        {
            //通过ViewData的方式保存下来 传递
            ViewData["数据的名字"] = "数据的值 可以有很多种数据类型";
            ViewData["name"] = "ken";
            ViewData["birthday"] = new DateTime(2000, 1, 1);
            ViewData["hobby"] = new string[] { "跑步", "阅读", "Coding" };

            return View();
        }

        public IActionResult ViewBagDemo()
        {
            ViewBag.数据的名字 = "数据的值 可以有很多种数据类型";

            ViewBag.Title = "ViewBag传值示例";
            ViewBag.Name = "ken";
            ViewBag.Birthday = new DateTime(2000, 1, 1);
            ViewBag.Hobby = new string[] { "跑步", "阅读", "Coding" };

            return View();
        }

        public IActionResult ViewModelDemo()
        {
            ViewBag.Title = "ViewModel传值示例";

            //人类的实例化
            var person = new Person
            {
                Name = "ken",
                Birthday = new DateTime(2000, 1, 1),
                Hobby = new string[] { "跑步", "阅读", "Coding" }
            };

            //把对象传递给页面
            //等同于 return View("ViewModelDemo", person);
            return View(person);
        }

        /// <summary>
        /// 控制器方法
        /// </summary>
        /// <returns></returns>
        public IActionResult AddTEST()
        {
            //1、new一个分类对象 
            var cate = new Category()
            {
                CateName = "手机1"
            };

            //2、添加数据
            //数据库上下文.表名[分类表].Add[操作(增删查改)](对象【分类数据】)
            _db.Categories.Add(cate);

            //3、保存 执行SQL（Insert）
            //  影响条数 = 数据库上下文.保存方法();
            //  判断执行 是成功还是失败
            var row = _db.SaveChanges();

            //return View();
            //    返回一个内容 文本
            return Content("添加数据");
        }

        public IActionResult Add()
        {
            //new一个分类对象 等同于数据
            var cate = new Category()
            {
                CateName = "手机"
            };

            //添加数据
            _db.Categories.Add(cate);

            //保存 执行SQL
            var row = _db.SaveChanges();

            //如果影响行数>0
            if (row > 0)
                return Content("添加成功");
            return Content("添加失败");
        }
        /// <summary>
        /// 方便我们调用方法
        /// 新增多条数据 
        /// </summary>
        /// <returns></returns>
        public IActionResult AddRange()
        {   
            //新增多条数据
            //new一个对象列表
            // 实例化一个列表 = new List<类>();
            //实例化了 分类列表
            var list = new List<Category>();

            //把“家具”分类对象 添加进list列表
            list.Add(new Category
            {
                CateName = "家具"
            });

            //把“家电”分类对象 添加进list列表
            list.Add(new Category
            {
                CateName = "家电"
            });

            //把“图书”分类对象 添加进list列表
            list.Add(new Category
            {
                CateName = "图书"
            });

            //添加数据
            //数据库上下文.表名.操作【添加多条】(列表数据)
            _db.Categories.AddRange(list);

            //保存 执行SQL
            var row = _db.SaveChanges();

            //如果影响行数>0
            if (row > 0)
                return Content("添加成功");
            return Content("添加失败");
        }
        /// <summary>
        /// 控制器方法 方便我们调用 /Test/AddGoods
        /// </summary>
        /// <returns></returns>
        public IActionResult AddGoods()
        {
            //新增一个商品数据
            //new一个商品对象 等同于数据
            var good = new Good()
            {
                Name = "华为手机P60",
                CateId=1,
                //互联网系统  图片用链接表示 "http://aa.com/img.jpg"
                Cover = "",
                Price=10,
                Stock=1,
                CreateTime=DateTime.Now,
            };

            //添加数据
            //数据库上下文_db.表名.操作(对象)
            _db.Goods.Add(good);

            //保存 执行SQL
            var row = _db.SaveChanges();

            //如果影响行数>0
            if (row > 0)
                return Content("添加成功");
            return Content("添加失败");

        }

        /// <summary>
        /// 查询列表
        /// </summary>
        /// <returns></returns>
        public IActionResult GetList()
        {
            //查询所有数据
            //  数据库上下文.表名.操作方法
            var list = _db.Categories.ToList();

            //查询条件                     x只是变量 是分类对象
            //  数据库上下文.表名.where[查询条件](具体条件【判断】).ToList()【基础前面的条件查询数据】执行SQL
            var list1 = _db.Categories.Where(x => x.CateName == "手机").ToList();

            //       null
            // Category cate=new Category();


            //列表没有实际查询（形成SQL）   可迭代列表           列表数据
            //IQueryable                 IEnumerable          IList

            //查询单条数据
            //_db.Categories.First()  当数据不存在时候 会报错
            //_db.Categories.FirstOrDefault(x=>x.Id==1)  当数据不存在的时候返回默认类型null
            //  数据库上下文.表名.取第一条数据(可选参数，条件)
            var cate2 = _db.Categories.FirstOrDefault(x => x.Id == 1);
            //等于
            var cate = _db.Categories.Where(x => x.Id == 1).FirstOrDefault();

            //      返回对象结果 object 是所有类型的父类
            return new ObjectResult(list);
        }

        //在Test控制器添加GetGoods方法，查询分类Id为1的所有商品数据

        /// <summary>
        /// 获取商品
        /// </summary>
        /// <returns></returns>
        public IActionResult GetGoods()
        {
            //查询分类Id为1的所有商品数据
            //数据库上下文.表名.操作方法
            var list = _db.Goods.Where(x=>x.CateId==1).ToList();
            return new ObjectResult(list);
        }
        /// <summary>
        /// 更新数据
        /// </summary>
        /// <returns></returns>
        public IActionResult Update()
        {
            //SQL update Category set CateName="手机111" where Id=1

            //查询Id为110的数据  null
            var model = _db.Categories.FirstOrDefault(x => x.Id == 111);

            //如果没有数据 返回提示
            if (model == null)
            {
                //做出合理的错误处理
                return Content("数据不存在");
            }

            //赋值 null.CateName
            model.CateName = "手机111";

            //更新
            //数据库上下文.表名.操作
            _db.Categories.Update(model);

            //保存 执行SQL
            var row = _db.SaveChanges();

            //如果影响行数>0
            if (row > 0)
                return Content("添加成功");
            return Content("添加失败");
        }
        /// <summary>
        /// 更新多个数据
        /// </summary>
        /// <returns></returns>
        public IActionResult UpdateRange()
        {
            //                       like '%手机%'  =  字符串Contains 包含某个字符串
            var list = _db.Categories.Where(x=>x.CateName.Contains("手机")).ToList();
            //遍历循环 对某个List进行循环遍历  逐个元素循环
            // foreach(var[声明变量] item[遍历元素的变量名] in list【列表对象】 )
            foreach (var item in list)
            {
                //赋值
                item.CateName = item.CateName + "（更新）";
            }

            //更新
            // UpdateRange
            _db.Categories.UpdateRange(list);

            //保存 执行SQL
            var row = _db.SaveChanges();

            //如果影响行数>0
            if (row > 0)
                return Content("添加成功");
            return Content("添加失败");
        }

        //在Test控制器添加UpdateGoods方法，1新增的数据分类Id为2
        public IActionResult UpdateGoods()
        {
            //把Id=65商品 更新为分类Id==1
            var model = _db.Goods.FirstOrDefault(x => x.Id == 65);

            if (model == null)
            {
                return Content("商品不存在");
            }
            //赋值
            model.CateId = 2;
            model.Name = "新名字";

            //更新操作
            _db.Goods.Update(model);

            var row = _db.SaveChanges();
            if(row>0)
            {
                return Content("成功");
            }
            return Content("失败");
        }
        
        /// <summary>
        /// 删除数据
        /// </summary>
        /// <returns></returns>
        public IActionResult Remove()
        {
            //查询Id为1的数据
            var model = _db.Categories.FirstOrDefault(x => x.Id == 1);

            //如果没有数据 返回提示
            if (model == null)
            {
                return Content("数据不存在");
            }

            //删除
            _db.Categories.Remove(model);

            //保存 执行SQL
            var row = _db.SaveChanges();

            //如果影响行数>0
            if (row > 0)
                return Content("删除成功");
            return Content("删除失败");
        }

        public IActionResult RemoveRange()
        {
            //把包含“家”的分类查出来
            var list = _db.Categories.Where(x => x.CateName.Contains("家")).ToList();

            //删除
            _db.Categories.RemoveRange(list);

            //保存 执行SQL
            var row = _db.SaveChanges();

            //如果影响行数>0
            if (row > 0)
                return Content("删除成功");
            return Content("删除失败");
        }

        //在Test控制器添加DeleteGoods方法，把1新增的数据删除
        public IActionResult DeleteGoods()
        {
            var model = _db.Goods.FirstOrDefault(x => x.Id == 65);
            
            if(model==null)
                return Content("数据不存在");

            _db.Goods.Remove(model);

            //保存 执行SQL
            var row = _db.SaveChanges();

            //如果影响行数>0
            if (row > 0)
                return Content("删除成功");
            return Content("删除失败");
        }


        public IActionResult OrderBy()
        {
            //查询一个商品分类           列表 
            var list = _db.Categories.ToList();
            //条件查询                       条件(lamda表达式 结果)
            var list1 = _db.Categories.Where(x=>x.CateName=="家具").ToList();
            var list2 = _db.Categories.Where(x=>x.CateName=="家具").Where(x=>x.Id>0).ToList();
            //链式
            //排序                     排序lamda表达式  select * from category order by id 正序的排序
            var list3 = _db.Categories.OrderBy(x=>x.Id).ToList();
            //排序                     排序lamda表达式  select * from category order by id desc 倒序的排序
            var lis4 = _db.Categories.OrderByDescending(x => x.Id).ToList();
            //第一排序分类名称 第二排序是Id                       混合排序
            var lis5 = _db.Categories.OrderByDescending(x => x.CateName).ThenBy(x => x.Id).ToList();
            return new ObjectResult(list);
        }
        //        练习
        //在Test控制器添加SoftGoods方法，查询商品数据并以分类Id倒序显示
        public IActionResult SoftGoods()
        {
            //查询商品数据 并以 分类Id 倒序 显示
            var list = _db.Goods.OrderByDescending(x => x.CateId).ToList();
            return new ObjectResult(list);
        }


        public IActionResult SkipAndTake()
        {
            //分类列表 126~131
            var list = _db.Categories.OrderBy(x => x.Id).ToList();
            //只要后面4个 一共6个 =》 跳过前面2个 取后面的。
            //跳过skip() 只管跳过 使用这个方法前 必须要有一个排序规则
            var list1 = _db.Categories.OrderBy(x => x.Id).Skip(2).ToList();
            //取前N个数据Take 只要前面4个
            var list2 = _db.Categories.OrderBy(x => x.Id).Take(4).ToList();
            //2~4个 126（不要） 127 128 129 
            var list3 = _db.Categories.OrderBy(x => x.Id).Skip(1).Take(3).ToList();
            //3~6
            var list4 = _db.Categories.OrderBy(x => x.Id).Skip(2).Take(4).ToList();

            //              10                      61
            //分页 一页数量PageSize 数据库总共的数量Total 算出页数
            //60/ 10  6
            //页数 ：total/pagesize+1
            //查询分类分页 1页2个 查询第二页 第一页跳过2
            var list5 = _db.Categories.OrderBy(x => x.Id).Skip(2).Take(2).ToList();

            //126
            //127

            //128
            //129

            //130
            //131
            //                                     pageIndex=1 skip=0
            //                                     pageIndex=2 skip=2
            //                                     pageIndex=3 skip=4
            //                                     pageIndex=x skip=（x-1）*pageSize

            //126
            //127
            //128

            //129
            //130
            //131
            //                                     pageIndex=1 skip=0   (1-1)*3  
            //                                     pageIndex=2 skip=3  (2-1)*3
            //                                     pageIndex=x skip=（x-1）*pageSize
            //每页数量
            int pageSize = 4;
            //页码
            int pageIndex = 2;

            var list6 = _db.Categories.OrderBy(x => x.Id)
                .Skip((pageIndex - 1) * pageSize)
                .Take(pageSize)  //一页的数量
                .ToList();

            return new ObjectResult(list);
        }
        //    练习
        //在Test控制器添加SkipGoods方法，查询以商品金额倒序的3-7个商品
        public IActionResult SkipGoods()
        {
            ///商品金额 倒序 的 3-7 个商品
            var list = _db.Goods.OrderByDescending(x => x.Price).Skip(2).Take(5).ToList();
            return new ObjectResult(list);
        }
        public IActionResult Any()
        {
            //判断列表有没有数据  有ture 没有就是false
            var result = _db.Categories.Any();
            //根据条件判断列表有没有数据 判断有没有 数据分类名称 == "家电"
            var result1 = _db.Categories.Where(x => x.CateName == "家电").Any();
            //等同于
            var result2 = _db.Categories.Any(x => x.CateName == "家电");
            return Content("");
        }

        //练习
        //在Test控制器添加AnyGoods方法，判断商品金额为100的商品是否存在
        public IActionResult AnyGoods()
        {
            var result = _db.Goods.Any(x => x.Price == 10000);
            //如果存在 返回"存在" 否则返回"不存在"
            if (result)
                return Content("存在");
            return Content("不存在");
        }

        public IActionResult Count()
        {
            //分类表数据总量
            var count = _db.Categories.Count();

            //待条件
            var count1 = _db.Categories.Count(x => x.CateName.Contains("家"));

            return new ObjectResult(count1);
        }

        public IActionResult Sum()
        {
            //商品金额进行求和 商品表的所有数据
            var sum1 = _db.Goods.Sum(x => x.Price);
            //根据条件求和
            var sum2 = _db.Goods.Where(x => x.CateId == 1).Sum(x => x.Price);

            //平均数
            var avg = _db.Goods.Average(x => x.Price);
            return new ObjectResult(sum1);
        }

        //        练习
        //在Test控制器添加CountGoods方法，查询商品金额为500-1000的商品数量
        public IActionResult CountGoods()
        {
            var count = _db.Goods.Count(x => x.Price >= 500 && x.Price <= 1000);
            return new ObjectResult(count);
        }
        //在Test控制器添加SumGoods方法，查询分类Id为“1”的商品总额


        public IActionResult Grouby()
        {
            //sql select CateId
            //查询某一分类分组数据
            //统计每一个分类的 商品数量\商品总额
            //        对一个字段进行分组    构造一个查询结果
            var list = _db.Goods.GroupBy(x => x.CateId).Select(x => new
            {
                //自己组装这个查询结果
                x.Key, //分组的字段CateId
                Count = x.Count(),
                //        对金额求和
                Sum = x.Sum(z => z.Price),
                Avg = x.Average(z => z.Price),
                //获取求和统计count  sum  avg
            }).ToList();
            return new ObjectResult(list);
        }

        //        练习
        //在Test控制器添加StockGoods方法，统计商品表每个分类的总库存Stock

        public IActionResult StockGoods()
        {
            var list = _db.Goods.GroupBy(x => x.CateId).Select(x => new
            {
                x.Key,//分组字段
                Stock = x.Sum(z => z.Stock)
            }).ToList();
            return new ObjectResult(list);
        }

        //       4
        //select Goods.Id, Goods.Name, Category.CateName from Goods
        //            1                2              3
        //inner join Category on  Goods.CateId = Category.Id

        public IActionResult Join()
        {
            //商品表  //1、要连接的表 2、需要连接的表    3、被连接的表
            var list = _db.Goods.Join(_db.Categories, x => x.CateId, y => y.Id,
                 //4、构造一个新的查询结果 把两个表的字段结合 
                 (x, y) => new
                 {
                     x.Id,
                     x.Name,
                     y.CateName
                 }).ToList();

            return new ObjectResult(list);
        }
        //练习
        //在Join控制器添加JoinGoods方法名，查询分类名称为“数码”的商品数据
    }
}
